"""
消息收集插件
功能：自动收集QQ群消息和私聊消息，保存到数据库

监听事件：
- 群消息（GroupMessageEvent）
- 私聊消息（PrivateMessageEvent）
- 消息撤回事件（NoticeEvent）
"""
import json
from typing import Dict, Any, Optional

from nonebot import on_message, on_notice
from nonebot.adapters.onebot.v11 import (
    Bot,
    GroupMessageEvent,
    PrivateMessageEvent,
    NoticeEvent,
    Message
)
from nonebot.log import logger

from src.common.django_db import (
    create_message_record,
    parse_qq_timestamp,
    mark_message_recalled,
    get_message_by_qq_message_id
)


# 创建消息监听器（优先级设为较低，确保不影响其他插件）
message_collector = on_message(priority=99, block=False)

# 创建通知监听器（用于监听消息撤回）
recall_notice = on_notice(priority=99, block=False)


def extract_message_text(message: Message) -> str:
    """
    从Message对象中提取纯文本内容
    
    Args:
        message: Message对象
        
    Returns:
        提取的纯文本内容
    """
    text_parts = []
    for segment in message:
        if segment.type == 'text':
            text_parts.append(str(segment.data.get('text', '')))
        elif segment.type == 'at':
            # @消息，提取被@的QQ号
            qq = segment.data.get('qq', '')
            text_parts.append(f"@QQ{qq}")
        elif segment.type == 'face':
            # 表情，提取表情ID
            face_id = segment.data.get('id', '')
            text_parts.append(f"[表情{face_id}]")
        elif segment.type == 'image':
            # 图片，提取图片URL或文件名
            file = segment.data.get('file', segment.data.get('url', ''))
            text_parts.append(f"[图片:{file}]")
        elif segment.type == 'record':
            # 语音
            file = segment.data.get('file', '')
            text_parts.append(f"[语音:{file}]")
        elif segment.type == 'video':
            # 视频
            file = segment.data.get('file', '')
            text_parts.append(f"[视频:{file}]")
        elif segment.type == 'file':
            # 文件
            file = segment.data.get('file', '')
            text_parts.append(f"[文件:{file}]")
        elif segment.type == 'share':
            # 分享链接
            url = segment.data.get('url', '')
            text_parts.append(f"[分享:{url}]")
        elif segment.type == 'json':
            # JSON消息
            data = segment.data.get('data', '')
            text_parts.append(f"[JSON:{data}]")
        elif segment.type == 'xml':
            # XML消息
            data = segment.data.get('data', '')
            text_parts.append(f"[XML:{data}]")
        else:
            # 其他类型，尝试转换为字符串
            text_parts.append(f"[{segment.type}]")
    
    return ''.join(text_parts)


def event_to_dict(event: Any) -> Dict[str, Any]:
    """
    将事件对象转换为字典（用于保存原始消息）
    
    Args:
        event: 事件对象
        
    Returns:
        事件字典
    """
    try:
        # 尝试获取事件的JSON表示
        if hasattr(event, 'json'):
            return event.json()
        elif hasattr(event, 'dict'):
            return event.dict()
        else:
            # 如果都没有，尝试手动构建
            result = {
                'type': type(event).__name__,
                'message_id': getattr(event, 'message_id', None),
                'user_id': getattr(event, 'user_id', None),
                'group_id': getattr(event, 'group_id', None),
                'time': getattr(event, 'time', None),
            }
            if hasattr(event, 'message'):
                result['message'] = str(event.message)
            return result
    except Exception as e:
        logger.warning(f"转换事件为字典时出错: {e}")
        return {'error': str(e), 'type': type(event).__name__}


@message_collector.handle()
async def handle_message_collect(bot: Bot, event: GroupMessageEvent | PrivateMessageEvent):
    """
    处理消息收集
    
    自动收集群消息和私聊消息，保存到数据库
    """
    try:
        # 判断消息类型
        if isinstance(event, GroupMessageEvent):
            message_type = 'group'
            group_id = event.group_id
        elif isinstance(event, PrivateMessageEvent):
            message_type = 'private'
            group_id = None
        else:
            # 未知类型，跳过
            return
        
        # 提取消息信息
        qq_message_id = event.message_id
        sender_qq = event.user_id
        message_time = parse_qq_timestamp(event.time)
        
        # 提取消息文本内容
        message_content = extract_message_text(event.message)
        
        # 如果消息内容为空，跳过（可能是纯图片、语音等）
        if not message_content.strip():
            message_content = "[非文本消息]"
        
        # 转换为原始消息字典
        raw_message = event_to_dict(event)
        
        # 检查消息是否已存在（避免重复保存）
        existing_message = await get_message_by_qq_message_id(qq_message_id)
        if existing_message:
            logger.debug(f"消息 {qq_message_id} 已存在，跳过保存")
            return
        
        # 保存到数据库
        await create_message_record(
            qq_message_id=qq_message_id,
            sender_qq=sender_qq,
            message_content=message_content,
            message_time=message_time,
            group_id=group_id,
            message_type=message_type,
            raw_message=raw_message
        )
        
        logger.info(
            f"✅ 已收集消息: [{message_type}] "
            f"消息ID={qq_message_id}, 发送者={sender_qq}, "
            f"群号={group_id}, 内容={message_content[:50]}..."
        )
        
    except Exception as e:
        logger.error(f"❌ 收集消息时出错: {e}")
        import traceback
        logger.error(traceback.format_exc())


@recall_notice.handle()
async def handle_message_recall(bot: Bot, event: NoticeEvent):
    """
    处理消息撤回事件
    
    当用户撤回消息时，更新数据库中的消息记录
    """
    try:
        # 检查是否是消息撤回通知
        if event.notice_type != 'group_recall' and event.notice_type != 'friend_recall':
            return
        
        # 提取撤回的消息ID
        qq_message_id = event.message_id
        
        if not qq_message_id:
            logger.warning("撤回事件中没有找到消息ID")
            return
        
        # 获取撤回时间
        recall_time = parse_qq_timestamp(event.time)
        
        # 更新数据库中的消息记录
        success = await mark_message_recalled(
            qq_message_id=qq_message_id,
            recalled_at=recall_time
        )
        
        if success:
            logger.info(f"✅ 已标记消息为撤回: 消息ID={qq_message_id}, 撤回时间={recall_time}")
        else:
            logger.warning(f"⚠️ 未找到要撤回的消息记录: 消息ID={qq_message_id}")
        
    except Exception as e:
        logger.error(f"❌ 处理消息撤回时出错: {e}")
        import traceback
        logger.error(traceback.format_exc())

